using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace EuropeEngulfed.NET
{
    class CombatMove : Move
    {
        public const string IMAGE_LIST_KEY = "Combat";

        private MapInfo.RegionID battleRegion;
        private Dictionary<PlayingPiece, int> combatLosses;
        private GameController.playerType attackingPlayer;
        private bool defenderRetreatedBeforeCombat;
        private List<OperationalMove> retreatBeforeCombatMoves;
        private bool defenderReinforced;
        private List<OperationalMove> reinforceBeforeCombat;
        private Dictionary<MapInfo.CountryID, int> specialActionsSpentOnReinforcements;
        public bool defenderCounterAttacked;
        private List<MovePieceOperationalMove> counterAttackingMoves;
        private List<MapInfo.CountryID> specialActionsSpentOnCounterAttacking;
        private Dictionary<PlayingPiece, int> counterAttackLosses;

        public CombatMove(GameTurn.GameDate gameDate, GameTurn.GamePhase gamePhase, GameTurn.GameSubPhase gameSubPhase,MapInfo.RegionID battleRegion, GameController.playerType attackingPlayer)
            : base(gameDate, gamePhase, gameSubPhase)
        {
            this.battleRegion = battleRegion;
            combatLosses = new Dictionary<PlayingPiece, int>();
            this.attackingPlayer = attackingPlayer;
            retreatBeforeCombatMoves = new List<OperationalMove>();
            defenderRetreatedBeforeCombat = false;
            defenderReinforced = false;
            reinforceBeforeCombat = new List<OperationalMove>();
            specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>();
            defenderCounterAttacked = false;
            counterAttackingMoves = new List<MovePieceOperationalMove>();
            specialActionsSpentOnCounterAttacking = new List<MapInfo.CountryID>();
            counterAttackLosses = new Dictionary<PlayingPiece, int>();
        }

        public bool CounterAttack
        {
            get
            {
                return defenderCounterAttacked;
            }

            set
            {
                defenderCounterAttacked = value;
            }
        }

        public bool RetreatBeforeCombat
        {
            get
            {
                return defenderRetreatedBeforeCombat;
            }

            set
            {
                defenderRetreatedBeforeCombat = value;
            }
        }

        public bool DefenderReinforced
        {
            get
            {
                return defenderReinforced;
            }

            set
            {
                defenderReinforced = value;
            }
        }

        public MapInfo.RegionID BattleRegion
        {
            get
            {
                return battleRegion;
            }
        }

        public void AddRetreatBeforeCombatMove(OperationalMove retreatBeforeCombat)
        {
            retreatBeforeCombatMoves.Add(retreatBeforeCombat);
        }

        public void AddReinforceBeforeCombatMove(OperationalMove reinforceBeforeCombat)
        {
            this.reinforceBeforeCombat.Add(reinforceBeforeCombat);
        }

        public void AddCounterAttackMove(MovePieceOperationalMove counterAttackMove)
        {
            counterAttackingMoves.Add(counterAttackMove);
        }

        public void SetReinforceSpecialActionsSpent(Dictionary<MapInfo.CountryID, int> SAsSpent)
        {
            if(SAsSpent != null)
                specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>(SAsSpent);
        }

        public void SetCounterAttackingSAsSpent(List<MapInfo.CountryID> SAsSpent)
        {
            if (SAsSpent != null)
                specialActionsSpentOnCounterAttacking = new List<MapInfo.CountryID>(SAsSpent);
        }

        public int GetNumSpecialActionsSpentByCountry(MapInfo.CountryID country)
        {
            int numSpecialActionsSpent = 0;
            if (specialActionsSpentOnReinforcements.ContainsKey(country))
                numSpecialActionsSpent = specialActionsSpentOnReinforcements[country];
            if (specialActionsSpentOnCounterAttacking.Contains(country))
                numSpecialActionsSpent++;
            if(defenderRetreatedBeforeCombat)
            {
                foreach(OperationalMove move in retreatBeforeCombatMoves)
                {
                    if(move is MovePieceOperationalMove)
                    {
                        if(GetEquivalentSupportCountry(((MovePieceOperationalMove)move).PieceMoved.CountryOwner) == country)
                        {
                            numSpecialActionsSpent++;
                            break;
                        }
                    }
                    else if(move is SeaMoveOperationalMove)
                    {
                        if(((SeaMoveOperationalMove)move).GetNumberOfPiecesTransportedForCountry(country) > 0)
                        {
                            numSpecialActionsSpent++;
                            break;
                        }
                    }
                }
            }
            return numSpecialActionsSpent;
        }

        public void DoBreakThroughGSUCombat(IGameStateInfoProvider gameInfoProvider, int numDefendingGSUGroundSupporting, int numAttackingGSUGroundSupporting, List<int> defendingDieRolls, List<int> attackingDieRolls, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSA, Random r)
        {
            int numDefendingGSUDogfighting;
            int numAttackingGSUDogfighting;
            List<GroundSupportUnit> axisGSUList = new List<GroundSupportUnit>();
            List<GroundSupportUnit> alliedGSUList = new List<GroundSupportUnit>();

            foreach (GroundSupportUnit GSU in gameInfoProvider.GetRegionsAxisGSUList(battleRegion))
            {
                if (attackingPlayer == GameController.playerType.AxisPlayer)
                {
                    if ((GSU.CountryOwner == MapInfo.CountryID.Italy && countriesSpendingSA.Contains(GSU.CountryOwner)) || (countriesSpendingSA.Contains(MapInfo.CountryID.Germany) && GSU.CountryOwner != MapInfo.CountryID.Italy))
                        axisGSUList.Add(GSU);
                }
                else
                    axisGSUList.Add(GSU);
            }

            foreach (GroundSupportUnit GSU in gameInfoProvider.GetRegionsAlliedGSUList(battleRegion))
            {
                if (attackingPlayer == GameController.playerType.AlliedPlayer)
                {
                    if (countriesSpendingSA.Contains(GSU.CountryOwner) || (countriesSpendingSA.Contains(MapInfo.CountryID.USA) && GSU.CountryOwner == MapInfo.CountryID.FreeFrance))
                        alliedGSUList.Add(GSU);
                }
                else
                    alliedGSUList.Add(GSU);
            }

            if (counterAttack)
            {
                numDefendingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? axisGSUList.Count - numDefendingGSUGroundSupporting : alliedGSUList.Count - numDefendingGSUGroundSupporting;
                numAttackingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? alliedGSUList.Count - numAttackingGSUGroundSupporting : axisGSUList.Count - numAttackingGSUGroundSupporting;
            }
            else
            {
                numDefendingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? alliedGSUList.Count - numDefendingGSUGroundSupporting : axisGSUList.Count - numDefendingGSUGroundSupporting;
                numAttackingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? axisGSUList.Count - numAttackingGSUGroundSupporting : alliedGSUList.Count - numAttackingGSUGroundSupporting;
            }

            for (int i = 0; i < numDefendingGSUDogfighting; i++)
                defendingDieRolls.Add(r.Next(6) + 1);

            for (int i = 0; i < numAttackingGSUDogfighting; i++)
                attackingDieRolls.Add(r.Next(6) + 1);
        }

        public void DoGSUCombat(IGameStateInfoProvider gameInfoProvider, int numDefendingGSUGroundSupporting, int numAttackingGSUGroundSupporting, List<int> defendingDieRolls, List<int> attackingDieRolls, bool counterAttack, Random r)
        {
            int numDefendingGSUDogfighting;
            int numAttackingGSUDogfighting;

            if (counterAttack)
            {
                numDefendingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? gameInfoProvider.GetRegionsAxisGSUList(battleRegion).Count - numDefendingGSUGroundSupporting : gameInfoProvider.GetRegionsAlliedGSUList(battleRegion).Count - numDefendingGSUGroundSupporting;
                numAttackingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? gameInfoProvider.GetRegionsAlliedGSUList(battleRegion).Count - numAttackingGSUGroundSupporting : gameInfoProvider.GetRegionsAxisGSUList(battleRegion).Count - numAttackingGSUGroundSupporting;
            }
            else
            {
                numDefendingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? gameInfoProvider.GetRegionsAlliedGSUList(battleRegion).Count - numDefendingGSUGroundSupporting : gameInfoProvider.GetRegionsAxisGSUList(battleRegion).Count - numDefendingGSUGroundSupporting;
                numAttackingGSUDogfighting = attackingPlayer == GameController.playerType.AxisPlayer ? gameInfoProvider.GetRegionsAxisGSUList(battleRegion).Count - numAttackingGSUGroundSupporting : gameInfoProvider.GetRegionsAlliedGSUList(battleRegion).Count - numAttackingGSUGroundSupporting;
            }

            for(int i = 0; i < numDefendingGSUDogfighting; i++)
                defendingDieRolls.Add(r.Next(6) + 1);

            for (int i = 0; i < numAttackingGSUDogfighting; i++)
                attackingDieRolls.Add(r.Next(6) + 1);
        }

        public void AssignLoss(PlayingPiece pieceToAssignLossTo, int stepLosses)
        {
            if(pieceToAssignLossTo is GroundSupportUnit)
            {
                combatLosses.Add(pieceToAssignLossTo, 1);
            }
            else
            {
                bool foundPiece = false;
                foreach(PlayingPiece piece in this.combatLosses.Keys)
                {
                    if(piece is Block)
                    {
                        Block blockToTest = ((Block)piece).Copy();
                        blockToTest.CurrentStrength -= (uint)combatLosses[piece];
                        if (blockToTest.Equals(pieceToAssignLossTo))
                        {
                            combatLosses[piece] += stepLosses;
                            foundPiece = true;
                            break;
                        }
                    }
                }

                if(!foundPiece)
                {
                    Block blockToAssignLossTo = ((Block)pieceToAssignLossTo).Copy();
                    combatLosses.Add(blockToAssignLossTo, stepLosses);
                }
            }
        }

        public void AssignCounterAttackLoss(PlayingPiece pieceToAssignLossTo, int stepLosses)
        {
            if (pieceToAssignLossTo is GroundSupportUnit)
            {
                counterAttackLosses.Add(pieceToAssignLossTo, 1);
            }
            else
            {
                bool foundPiece = false;
                foreach (PlayingPiece piece in this.counterAttackLosses.Keys)
                {
                    if (piece is Block)
                    {
                        Block blockToTest = ((Block)piece).Copy();
                        blockToTest.CurrentStrength -= (uint)counterAttackLosses[piece];
                        if (blockToTest.Equals(pieceToAssignLossTo))
                        {
                            counterAttackLosses[piece] += stepLosses;
                            foundPiece = true;
                            break;
                        }
                    }
                }

                if (!foundPiece)
                {
                    Block blockToAssignLossTo = ((Block)pieceToAssignLossTo).Copy();
                    counterAttackLosses.Add(blockToAssignLossTo, stepLosses);
                }
            }
        }

        public void ProcessGSUListModification(IGameStateInfoProvider gameInfoProvider, List<GroundSupportUnit> listToModify, MapInfo.RegionID region, bool processDisembarkation, GameController.playerType playerListToModify)
        {
            if (!defenderRetreatedBeforeCombat)
            {
                foreach (OperationalMove reinforceMove in this.reinforceBeforeCombat)
                {
                    if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(((MovePieceOperationalMove)reinforceMove).PieceMoved.CountryOwner))
                    || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(((MovePieceOperationalMove)reinforceMove).PieceMoved.CountryOwner)))
                        ((MovePieceOperationalMove)reinforceMove).ProcessGSUListModification(listToModify, region);
                }

                foreach (PlayingPiece pieceSustainingLosses in combatLosses.Keys)
                {
                    if (pieceSustainingLosses is GroundSupportUnit)
                    {
                        foreach (GroundSupportUnit GSU in listToModify)
                        {
                            if (GSU.Equals((GroundSupportUnit)pieceSustainingLosses))
                            {
                                listToModify.Remove(GSU);
                                break;
                            }
                        }
                    }
                }

                if(this.defenderCounterAttacked)
                {
                    foreach (MovePieceOperationalMove counterAttackMove in this.counterAttackingMoves)
                    {
                        if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(counterAttackMove.PieceMoved.CountryOwner))
                        || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(counterAttackMove.PieceMoved.CountryOwner)))
                            counterAttackMove.ProcessGSUListModification(listToModify, region);
                    }

                    foreach (PlayingPiece pieceSustainingLosses in counterAttackLosses.Keys)
                    {
                        if (pieceSustainingLosses is GroundSupportUnit)
                        {
                            foreach (GroundSupportUnit GSU in listToModify)
                            {
                                if (GSU.Equals((GroundSupportUnit)pieceSustainingLosses))
                                {
                                    listToModify.Remove(GSU);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                foreach (OperationalMove retreatBeforeCombat in retreatBeforeCombatMoves)
                {
                    if (retreatBeforeCombat is MovePieceOperationalMove)
                    {
                        if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(((MovePieceOperationalMove)retreatBeforeCombat).PieceMoved.CountryOwner))
                        || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(((MovePieceOperationalMove)retreatBeforeCombat).PieceMoved.CountryOwner)))
                            ((MovePieceOperationalMove)retreatBeforeCombat).ProcessGSUListModification(listToModify, region);
                    }
                    else if (retreatBeforeCombat is SeaMoveOperationalMove)
                    {
                        if ((playerListToModify == GameController.playerType.AlliedPlayer && ((SeaMoveOperationalMove)retreatBeforeCombat).Player == GameController.playerType.AlliedPlayer)
                        || (playerListToModify == GameController.playerType.AxisPlayer && ((SeaMoveOperationalMove)retreatBeforeCombat).Player == GameController.playerType.AxisPlayer))
                            ((SeaMoveOperationalMove)retreatBeforeCombat).ProcessGSUListModification(listToModify, region, processDisembarkation);
                    }
                }
            }
        }

        public void ProcessBlockListModification(IGameStateInfoProvider gameInfoProvider, List<Block> listToModify, MapInfo.RegionID region, bool processDisembarkation, GameController.playerType playerListToModify)
        {
            if(defenderRetreatedBeforeCombat)
            {
                foreach (OperationalMove retreatBeforeCombat in retreatBeforeCombatMoves)
                {
                    if (retreatBeforeCombat is MovePieceOperationalMove)
                    {
                        if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(((MovePieceOperationalMove)retreatBeforeCombat).PieceMoved.CountryOwner))
                            || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(((MovePieceOperationalMove)retreatBeforeCombat).PieceMoved.CountryOwner)))
                            ((MovePieceOperationalMove)retreatBeforeCombat).ProcessBlockListModification(listToModify, region);
                    }
                    else if (retreatBeforeCombat is SeaMoveOperationalMove)
                    {
                        if ((playerListToModify == GameController.playerType.AlliedPlayer && ((SeaMoveOperationalMove)retreatBeforeCombat).Player == GameController.playerType.AlliedPlayer)
                        || (playerListToModify == GameController.playerType.AxisPlayer && ((SeaMoveOperationalMove)retreatBeforeCombat).Player == GameController.playerType.AxisPlayer))
                            ((SeaMoveOperationalMove)retreatBeforeCombat).ProcessBlockListModification(listToModify, region, processDisembarkation);
                    }
                }
            }

            foreach (OperationalMove reinforceMove in this.reinforceBeforeCombat)
            {
                if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(((MovePieceOperationalMove)reinforceMove).PieceMoved.CountryOwner))
                || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(((MovePieceOperationalMove)reinforceMove).PieceMoved.CountryOwner)))
                    ((MovePieceOperationalMove)reinforceMove).ProcessBlockListModification(listToModify, region);
            }

            if(this.battleRegion == region)
            {
                foreach (PlayingPiece pieceSustainingLosses in combatLosses.Keys)
                {
                    if (pieceSustainingLosses is Block)
                    {
                        foreach (Block block in listToModify)
                        {
                            if (block.Equals((Block)pieceSustainingLosses))
                            {
                                if (combatLosses[pieceSustainingLosses] >= block.CurrentStrength)
                                    listToModify.Remove(block);
                                else
                                    block.CurrentStrength -= (uint)combatLosses[pieceSustainingLosses];
                                break;
                            }
                        }
                    }
                }
            }

            if(this.defenderCounterAttacked)
            {
                foreach (MovePieceOperationalMove counterAttackMove in this.counterAttackingMoves)
                {
                    if ((playerListToModify == GameController.playerType.AlliedPlayer && gameInfoProvider.IsAlliedCountry(counterAttackMove.PieceMoved.CountryOwner))
                    || (playerListToModify == GameController.playerType.AxisPlayer && gameInfoProvider.IsAxisCountry(counterAttackMove.PieceMoved.CountryOwner)))
                        counterAttackMove.ProcessBlockListModification(listToModify, region);
                }

                if(this.battleRegion == region)
                {
                    foreach (PlayingPiece pieceSustainingLosses in counterAttackLosses.Keys)
                    {
                        if (pieceSustainingLosses is Block)
                        {
                            foreach (Block block in listToModify)
                            {
                                if (block.Equals((Block)pieceSustainingLosses))
                                {
                                    if (counterAttackLosses[pieceSustainingLosses] >= block.CurrentStrength)
                                        listToModify.Remove(block);
                                    else
                                        block.CurrentStrength -= (uint)counterAttackLosses[pieceSustainingLosses];
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        public override bool IsLegal(IGameStateInfoProvider gameStateInfoProvider, ref string ruleString)
        {
            if (gameStateInfoProvider.GetRegionsAlliedBlockList(this.battleRegion).Count > 0 && gameStateInfoProvider.GetRegionsAxisBlockList(this.battleRegion).Count > 0)
                return true;
            else
                return false;
        }

        public static MapInfo.CountryID GetEquivalentSupportCountry(MapInfo.CountryID country)
        {
            switch (country)
            {
                case MapInfo.CountryID.Bulgaria:
                case MapInfo.CountryID.Hungary:
                case MapInfo.CountryID.Rumania:
                case MapInfo.CountryID.Finland:
                    return MapInfo.CountryID.Germany;
                case MapInfo.CountryID.FreeFrance:
                    return MapInfo.CountryID.USA;
                default:
                    return country;
            }
        }

        public List<MapInfo.CountryID> GetListOfCountryNeedingToSpendSA()
        {
            List<MapInfo.CountryID> countriesThatNeedToSpendSA = new List<MapInfo.CountryID>();
            if(this.RetreatBeforeCombat)
            {
                foreach (OperationalMove retreatBeforeCombatMove in this.retreatBeforeCombatMoves)
                {
                    if (retreatBeforeCombatMove is MovePieceOperationalMove)
                    {
                        if (!countriesThatNeedToSpendSA.Contains(GetEquivalentSupportCountry(((MovePieceOperationalMove)retreatBeforeCombatMove).PieceMoved.CountryOwner)))
                            countriesThatNeedToSpendSA.Add(GetEquivalentSupportCountry(((MovePieceOperationalMove)retreatBeforeCombatMove).PieceMoved.CountryOwner));
                    }
                    else if (retreatBeforeCombatMove is SeaMoveOperationalMove)
                    {
                        foreach (PlayingPiece pieceMoved in ((SeaMoveOperationalMove)retreatBeforeCombatMove).GetListOfPiecesBeingTransported())
                        {
                            if (!countriesThatNeedToSpendSA.Contains(GetEquivalentSupportCountry(pieceMoved.CountryOwner)))
                                countriesThatNeedToSpendSA.Add(GetEquivalentSupportCountry(pieceMoved.CountryOwner));
                        }

                        if(((SeaMoveOperationalMove)retreatBeforeCombatMove).SeaRegionTransportedThrough == MapInfo.RegionID.MediteraneanSea)
                        {
                            if (!countriesThatNeedToSpendSA.Contains(MapInfo.CountryID.Italy))
                                countriesThatNeedToSpendSA.Add(MapInfo.CountryID.Italy);
                        }
                    }
                }
            }

            return countriesThatNeedToSpendSA;
        }

        public List<OperationalMove> GetListOfRetreats()
        {
            if (this.RetreatBeforeCombat)
                return retreatBeforeCombatMoves;
            else
                return new List<OperationalMove>();
        }

        protected override void ProcessMove(GameState gameState)
        {
            LandRegionState battleRegionState = (LandRegionState)gameState.GetRegionState(this.battleRegion);
            if (defenderRetreatedBeforeCombat)
            {
                List<MapInfo.CountryID> countriesThatNeedToSpendSA = GetListOfCountryNeedingToSpendSA();

                foreach (MapInfo.CountryID country in countriesThatNeedToSpendSA)
                {
                    gameState.SpendSpecialAction(country);
                }

                foreach (OperationalMove retreatBeforeCombatMove in retreatBeforeCombatMoves)
                {
                    retreatBeforeCombatMove.ProcessMoveOnly(gameState);
                }
            }

            foreach (OperationalMove reinforceBeforeCombatMove in this.reinforceBeforeCombat)
            {
                reinforceBeforeCombatMove.ProcessMoveOnly(gameState);
            }

            foreach(MapInfo.CountryID country in this.specialActionsSpentOnReinforcements.Keys)
            {
                for (int i = 0; i < specialActionsSpentOnReinforcements[country]; i++ )
                    gameState.SpendSpecialAction(country);
            }

            foreach (PlayingPiece pieceSustainingLosses in combatLosses.Keys)
            {
                if (combatLosses[pieceSustainingLosses] > 0)
                {
                    for (int i = 0; battleRegionState.GetPlayingPieceAt(i) != null; i++)
                    {
                        PlayingPiece playingPieceSustainingLoss = battleRegionState.GetPlayingPieceAt(i);
                        if (playingPieceSustainingLoss.Equals(pieceSustainingLosses))
                        {
                            if (playingPieceSustainingLoss is GroundSupportUnit)
                            {
                                battleRegionState.ReturnPlayingPieceToForcePool(gameState, playingPieceSustainingLoss);
                            }
                            else
                            {
                                Block blockSustainingLoss = (Block)playingPieceSustainingLoss;
                                if (blockSustainingLoss.CurrentStrength > combatLosses[pieceSustainingLosses])
                                {
                                    blockSustainingLoss.CurrentStrength -= (uint)combatLosses[pieceSustainingLosses];
                                }
                                else
                                    battleRegionState.ReturnPlayingPieceToForcePool(gameState, playingPieceSustainingLoss);
                            }
                            break;
                        }
                    }
                }
            }
            battleRegionState.RemoveGSUAndBeachHeadsAloneWithGroundUnits(gameState);

            if(this.defenderCounterAttacked)
            {
                foreach (MapInfo.CountryID country in this.specialActionsSpentOnCounterAttacking)
                {
                    gameState.SpendSpecialAction(country);
                }   

                foreach (MovePieceOperationalMove counterAttackMove in this.counterAttackingMoves)
                {
                    counterAttackMove.ProcessMoveOnly(gameState);
                }

                foreach (PlayingPiece pieceSustainingLosses in counterAttackLosses.Keys)
                {
                    if (counterAttackLosses[pieceSustainingLosses] > 0)
                    {
                        for (int i = 0; battleRegionState.GetPlayingPieceAt(i) != null; i++)
                        {
                            PlayingPiece playingPieceSustainingLoss = battleRegionState.GetPlayingPieceAt(i);
                            if (playingPieceSustainingLoss.Equals(pieceSustainingLosses))
                            {
                                if (playingPieceSustainingLoss is GroundSupportUnit)
                                {
                                    battleRegionState.ReturnPlayingPieceToForcePool(gameState, playingPieceSustainingLoss);
                                }
                                else
                                {
                                    Block blockSustainingLoss = (Block)playingPieceSustainingLoss;
                                    if (blockSustainingLoss.CurrentStrength > counterAttackLosses[pieceSustainingLosses])
                                    {
                                        blockSustainingLoss.CurrentStrength -= (uint)counterAttackLosses[pieceSustainingLosses];
                                    }
                                    else
                                        battleRegionState.ReturnPlayingPieceToForcePool(gameState, playingPieceSustainingLoss);
                                }
                                break;
                            }
                        }
                    }
                }
                battleRegionState.RemoveGSUAndBeachHeadsAloneWithGroundUnits(gameState);
            }

            if(gameState.IsAxisCountry(battleRegionState.CountryControl))
            {
                if(battleRegionState.AnyAlliedBlocksRemaining(gameState) && ! battleRegionState.AnyAxisBlocksRemaining(gameState))
                {
                    battleRegionState.CountryControl = battleRegionState.GetPlayingPieceAt(0).CountryOwner;
                }
            }
            else if(gameState.IsAlliedCountry(battleRegionState.CountryControl))
            {
                if (battleRegionState.AnyAxisBlocksRemaining(gameState) && !battleRegionState.AnyAlliedBlocksRemaining(gameState))
                {
                    battleRegionState.CountryControl = battleRegionState.GetPlayingPieceAt(0).CountryOwner;
                }
            }

            if(attackingPlayer == GameController.playerType.AlliedPlayer)
            {
                /*If combat against the Vichy unit is conducted
                    solely by U.S. units, the Vichy unit is always eliminated without defending
                    at the start of the Combat round involving the Vichy unit.*/
                bool OnlyUSUnitsParticipating = true;
                for (int i = 0; battleRegionState.GetBlockAt(i) != null; i++)
                {
                    if (gameState.IsAlliedCountry(battleRegionState.GetBlockAt(i).CountryOwner))
                    {
                        if (battleRegionState.GetBlockAt(i).CountryOwner != MapInfo.CountryID.USA && battleRegionState.GetBlockAt(i).CountryOwner != MapInfo.CountryID.FreeFrance)
                        {
                            OnlyUSUnitsParticipating = false;
                            break;
                        }
                    }
                }

                if (OnlyUSUnitsParticipating)
                {
                    for (int i = 0; battleRegionState.GetGSUAt(i) != null; i++)
                    {
                        if (gameState.IsAlliedCountry(battleRegionState.GetGSUAt(i).CountryOwner))
                        {
                            if (battleRegionState.GetGSUAt(i).CountryOwner != MapInfo.CountryID.USA && battleRegionState.GetGSUAt(i).CountryOwner != MapInfo.CountryID.FreeFrance)
                            {
                                OnlyUSUnitsParticipating = false;
                                break;
                            }
                        }
                    }
                }

                if(OnlyUSUnitsParticipating)
                {
                    for (int i = 0; battleRegionState.GetBlockAt(i) != null; i++)
                    {
                        if (battleRegionState.GetBlockAt(i).CountryOwner == MapInfo.CountryID.VichyFrance)
                            battleRegionState.ReturnPlayingPieceToForcePool(gameState, battleRegionState.GetBlockAt(i));
                    }
                }
            }
            
            battleRegionState.NewBattleState = LandRegionState.NewBattleStatus.notNew;
            if (battleRegionState.FortLevel == LandRegionState.FieldFortificationLevel.fieldfortification && battleRegionState.IsContested(gameState))
                battleRegionState.FortLevel = LandRegionState.FieldFortificationLevel.none;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("Move");
            System.Xml.XmlAttribute typeAttr = xml.CreateAttribute("Type");
            System.Xml.XmlAttribute battleRegionAttr = xml.CreateAttribute("battleRegion");
            System.Xml.XmlAttribute defenderRetreatedBeforeCombatAttr = xml.CreateAttribute("defenderRetreatedBeforeCombat");
            System.Xml.XmlAttribute defenderCounterAttackedAttr = xml.CreateAttribute("defenderCounterAttacked");
            System.Xml.XmlAttribute defenderReinforcedAttr = xml.CreateAttribute("defenderReinforced");
            System.Xml.XmlAttribute attackingPlayerAttr = xml.CreateAttribute("attackingPlayer");
            System.Xml.XmlNode combatLossesNode = xml.CreateElement("CombatLosses");
            System.Xml.XmlNode retreatBeforeCombatMovesNode = xml.CreateElement("retreatBeforeCombatMoves");
            System.Xml.XmlNode reinforceBeforeCombatNode = xml.CreateElement("reinforceBeforeCombat");
            System.Xml.XmlNode specialActionsSpentOnReinforcementstNode = xml.CreateElement("specialActionsSpentOnReinforcements");
            System.Xml.XmlNode counterAttackingMovesNode = xml.CreateElement("counterAttackingMoves");
            System.Xml.XmlNode specialActionsSpentOnCounterAttackingNode = xml.CreateElement("specialActionsSpentOnCounterAttacking");
            System.Xml.XmlNode counterAttackLossesNode = xml.CreateElement("counterAttackLosses");

            nodeToReturn.AppendChild(gameTurn.Serialise(xml));
            typeAttr.Value = this.GetType().ToString();
            battleRegionAttr.Value = Enum.GetName(typeof(MapInfo.RegionID), this.battleRegion);
            defenderRetreatedBeforeCombatAttr.Value = defenderRetreatedBeforeCombat.ToString();
            defenderCounterAttackedAttr.Value = defenderCounterAttacked.ToString();
            defenderReinforcedAttr.Value = defenderReinforced.ToString();
            attackingPlayerAttr.Value = Enum.GetName(typeof(GameController.playerType), this.attackingPlayer);
            nodeToReturn.Attributes.Append(typeAttr);
            nodeToReturn.Attributes.Append(battleRegionAttr);
            nodeToReturn.Attributes.Append(defenderRetreatedBeforeCombatAttr);
            nodeToReturn.Attributes.Append(defenderCounterAttackedAttr);
            nodeToReturn.Attributes.Append(defenderReinforcedAttr);
            nodeToReturn.Attributes.Append(attackingPlayerAttr);
            foreach(PlayingPiece piece in combatLosses.Keys)
            {
                System.Xml.XmlNode combatLossNode = xml.CreateElement("CombatLoss");
                System.Xml.XmlNode combatLossAmount = xml.CreateElement("CombatLossAmount");
                if (piece is Block)
                {
                    combatLossNode.AppendChild(((Block)piece).Serialise(xml));
                }
                else if (piece is GroundSupportUnit)
                {
                    combatLossNode.AppendChild(((GroundSupportUnit)piece).Serialise(xml));
                }
                else
                    throw new InvalidOperationException();

                combatLossAmount.InnerText = combatLosses[piece].ToString();
                combatLossNode.AppendChild(combatLossAmount);
                combatLossesNode.AppendChild(combatLossNode);
            }
            nodeToReturn.AppendChild(combatLossesNode);

            foreach(OperationalMove retreatMove in retreatBeforeCombatMoves)
            {
                retreatBeforeCombatMovesNode.AppendChild(retreatMove.Serialise(xml));
            }
            nodeToReturn.AppendChild(retreatBeforeCombatMovesNode);

            foreach (OperationalMove reinforceMove in reinforceBeforeCombat)
            {
                reinforceBeforeCombatNode.AppendChild(reinforceMove.Serialise(xml));
            }
            nodeToReturn.AppendChild(reinforceBeforeCombatNode);

            foreach (MapInfo.CountryID country in specialActionsSpentOnReinforcements.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlNode specialActionSpentNode = xml.CreateElement("specialActionSpent");
                countryAttr.Value = Enum.GetName(country.GetType(), country);
                specialActionSpentNode.Attributes.Append(countryAttr);
                specialActionSpentNode.InnerText = specialActionsSpentOnReinforcements[country].ToString();
                specialActionsSpentOnReinforcementstNode.AppendChild(specialActionSpentNode);
            }
            nodeToReturn.AppendChild(specialActionsSpentOnReinforcementstNode);

            foreach (OperationalMove counterAttackMove in counterAttackingMoves)
            {
                counterAttackingMovesNode.AppendChild(counterAttackMove.Serialise(xml));
            }
            nodeToReturn.AppendChild(counterAttackingMovesNode);

            foreach (MapInfo.CountryID country in specialActionsSpentOnCounterAttacking)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlNode specialActionSpentNode = xml.CreateElement("specialActionSpent");
                countryAttr.Value = Enum.GetName(country.GetType(), country);
                specialActionSpentNode.Attributes.Append(countryAttr);
                specialActionsSpentOnCounterAttackingNode.AppendChild(specialActionSpentNode);
            }
            nodeToReturn.AppendChild(specialActionsSpentOnCounterAttackingNode);

            foreach (PlayingPiece piece in counterAttackLosses.Keys)
            {
                System.Xml.XmlNode combatLossNode = xml.CreateElement("CombatLoss");
                System.Xml.XmlNode combatLossAmount = xml.CreateElement("CombatLossAmount");
                if (piece is Block)
                {
                    combatLossNode.AppendChild(((Block)piece).Serialise(xml));
                }
                else if (piece is GroundSupportUnit)
                {
                    combatLossNode.AppendChild(((GroundSupportUnit)piece).Serialise(xml));
                }
                else
                    throw new InvalidOperationException();

                combatLossAmount.InnerText = counterAttackLosses[piece].ToString();
                combatLossNode.AppendChild(combatLossAmount);
                counterAttackLossesNode.AppendChild(combatLossNode);
            }
            nodeToReturn.AppendChild(counterAttackLossesNode);

            return nodeToReturn;
        }

        public new static Move Deserialise(System.Xml.XmlNode node)
        {
            if (node.Attributes["Type"].Value == typeof(CombatMove).ToString() && node.Name == "Move")
            {
                System.Xml.XmlNode combatLossesNode = node.SelectSingleNode("CombatLosses");
                System.Xml.XmlNode retreatBeforeCombatMovesNode = node.SelectSingleNode("retreatBeforeCombatMoves");
                System.Xml.XmlNode reinforceBeforeCombatNode = node.SelectSingleNode("reinforceBeforeCombat");
                System.Xml.XmlNode specialActionsSpentOnReinforcementstNode = node.SelectSingleNode("specialActionsSpentOnReinforcements");
                System.Xml.XmlNode counterAttackingMovesNode = node.SelectSingleNode("counterAttackingMoves");
                System.Xml.XmlNode specialActionsSpentOnCounterAttackingNode = node.SelectSingleNode("specialActionsSpentOnCounterAttacking");
                System.Xml.XmlNode counterAttackLossesNode = node.SelectSingleNode("counterAttackLosses");
                GameTurn parsedGameTurn = GameTurn.Deserialise(node.SelectSingleNode("GameTurn"));
                CombatMove combatMoveToReturn = new CombatMove(parsedGameTurn.CurrentGameDate, parsedGameTurn.CurrentGamePhase, parsedGameTurn.CurrentGameSubPhase, (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["battleRegion"].Value), (GameController.playerType)Enum.Parse(typeof(GameController.playerType), node.Attributes["attackingPlayer"].Value));
                combatMoveToReturn.defenderRetreatedBeforeCombat = bool.Parse(node.Attributes["defenderRetreatedBeforeCombat"].Value);
                combatMoveToReturn.defenderCounterAttacked = bool.Parse(node.Attributes["defenderCounterAttacked"].Value);
                if (node.Attributes["defenderReinforced"] != null) //To support older save files that did not have this
                    combatMoveToReturn.defenderReinforced = bool.Parse(node.Attributes["defenderReinforced"].Value);
                foreach (System.Xml.XmlNode combatLossNode in combatLossesNode)
                {
                    PlayingPiece piece = null;
                    int lossAmount = 0;
                    foreach (System.Xml.XmlNode innerCombatNode in combatLossNode)
                    {
                        if (innerCombatNode.Name == "CombatLossAmount")
                            lossAmount = int.Parse(innerCombatNode.InnerText);
                        else if (innerCombatNode.Name == "GSU")
                        {
                            piece = GroundSupportUnit.Deserialise(innerCombatNode);
                        }
                        else if (innerCombatNode.Name == "Block")
                        {
                            piece = Block.Deserialise(innerCombatNode);
                        }
                    }
                    combatMoveToReturn.combatLosses.Add(piece, lossAmount);
                }

                foreach (System.Xml.XmlNode retreatBeforeCombatMoveNode in retreatBeforeCombatMovesNode)
                {
                    combatMoveToReturn.retreatBeforeCombatMoves.Add((OperationalMove)Move.Deserialise(retreatBeforeCombatMoveNode));
                }

                foreach (System.Xml.XmlNode reinforceMoveNode in reinforceBeforeCombatNode)
                {
                    combatMoveToReturn.reinforceBeforeCombat.Add((OperationalMove)Move.Deserialise(reinforceMoveNode));
                }

                foreach (System.Xml.XmlNode specialActionsSpentNode in specialActionsSpentOnReinforcementstNode)
                {
                    combatMoveToReturn.specialActionsSpentOnReinforcements.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), specialActionsSpentNode.Attributes["country"].Value), int.Parse(specialActionsSpentNode.InnerText));
                }

                foreach (System.Xml.XmlNode counterAttackMoveNode in counterAttackingMovesNode)
                {
                    combatMoveToReturn.counterAttackingMoves.Add((MovePieceOperationalMove)MovePieceOperationalMove.Deserialise(counterAttackMoveNode));
                }

                foreach (System.Xml.XmlNode specialActionSpentOnCounterAttackingNode in specialActionsSpentOnCounterAttackingNode)
                {
                    combatMoveToReturn.specialActionsSpentOnCounterAttacking.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), specialActionSpentOnCounterAttackingNode.Attributes["country"].Value));
                }

                foreach (System.Xml.XmlNode counterAttackLossNode in counterAttackLossesNode)
                {
                    PlayingPiece piece = null;
                    int lossAmount = 0;
                    foreach (System.Xml.XmlNode innerCounterAttackNode in counterAttackLossNode)
                    {
                        if (innerCounterAttackNode.Name == "CombatLossAmount")
                            lossAmount = int.Parse(innerCounterAttackNode.InnerText);
                        else if (innerCounterAttackNode.Name == "GSU")
                        {
                            piece = GroundSupportUnit.Deserialise(innerCounterAttackNode);
                        }
                        else if (innerCounterAttackNode.Name == "Block")
                        {
                            piece = Block.Deserialise(innerCounterAttackNode);
                        }
                    }
                    combatMoveToReturn.counterAttackLosses.Add(piece, lossAmount);
                }

                return combatMoveToReturn;
            }
            else
                throw new InvalidOperationException();
        }

        public override System.Windows.Forms.TreeNode GetMoveTreeNode(System.Windows.Forms.TreeView treeView)
        {
            System.Windows.Forms.TreeNode nodeToReturn = new System.Windows.Forms.TreeNode();
            if (attackingPlayer == GameController.playerType.AlliedPlayer)
                nodeToReturn.Text = "Allied Player Attack in " + MapInfo.GetRegionName(battleRegion);
            else
                nodeToReturn.Text = "Axis Player Attack in " + MapInfo.GetRegionName(battleRegion);
            if(!treeView.ImageList.Images.ContainsKey(IMAGE_LIST_KEY))
            {
                System.Reflection.Assembly thisExe;
                thisExe = System.Reflection.Assembly.GetExecutingAssembly();
                System.IO.Stream file;
                file = thisExe.GetManifestResourceStream("EuropeEngulfed.NET.Resources.Hits.bmp");
                Bitmap b = (Bitmap)Bitmap.FromStream(file);
                b.MakeTransparent(Color.FromArgb(128,128,128));
                treeView.ImageList.Images.Add(IMAGE_LIST_KEY, b);
                file.Dispose();
            }
            nodeToReturn.ImageIndex = treeView.ImageList.Images.IndexOfKey(IMAGE_LIST_KEY);
            nodeToReturn.SelectedImageIndex = nodeToReturn.ImageIndex;

            foreach(PlayingPiece piece in combatLosses.Keys)
            {
                System.Windows.Forms.TreeNode combatLossNode = new System.Windows.Forms.TreeNode();
                if (piece is GroundSupportUnit)
                    combatLossNode.Text = "GSU Destroyed";
                else
                    combatLossNode.Text = combatLosses[piece] + "-step loss";
                if(!treeView.ImageList.Images.ContainsKey(piece.GetTreeViewImageListKey(false)))
                {
                    if(piece is Block)
                    {
                        Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                        Graphics g = Graphics.FromImage(b);
                        PlayingPieceGraphics.PaintBlockFace(g, (Block)piece, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), false);
                        treeView.ImageList.Images.Add(piece.GetTreeViewImageListKey(false), b);
                    }
                    else if(piece is GroundSupportUnit)
                    {
                        Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                        Graphics g = Graphics.FromImage(b);
                        PlayingPieceGraphics.PaintGSUFace(g, (GroundSupportUnit)piece, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), false);
                        treeView.ImageList.Images.Add(piece.GetTreeViewImageListKey(false), b);
                    }
                }

                combatLossNode.ImageIndex = treeView.ImageList.Images.IndexOfKey(piece.GetTreeViewImageListKey(false));
                combatLossNode.SelectedImageIndex = combatLossNode.ImageIndex;
                nodeToReturn.Nodes.Add(combatLossNode);
            }

            if(retreatBeforeCombatMoves.Count > 0)
            {
                System.Windows.Forms.TreeNode retreatBeforeCombatNode = new System.Windows.Forms.TreeNode("Retreat Before Combat");
                foreach(OperationalMove opMove in retreatBeforeCombatMoves)
                {
                    retreatBeforeCombatNode.Nodes.Add(opMove.GetMoveTreeNode(treeView));
                }
                nodeToReturn.Nodes.Add(retreatBeforeCombatNode);
            }

            if (reinforceBeforeCombat.Count > 0)
            {
                System.Windows.Forms.TreeNode reinforceBeforeCombatNode = new System.Windows.Forms.TreeNode("Reinforce Before Combat");
                foreach (OperationalMove opMove in reinforceBeforeCombat)
                {
                    reinforceBeforeCombatNode.Nodes.Add(opMove.GetMoveTreeNode(treeView));
                }
                nodeToReturn.Nodes.Add(reinforceBeforeCombatNode);
            }

            if(this.CounterAttack)
            {
                System.Windows.Forms.TreeNode counterAttackNode = new System.Windows.Forms.TreeNode("CounterAttack");
                foreach (MovePieceOperationalMove opMove in counterAttackingMoves)
                {
                    counterAttackNode.Nodes.Add(opMove.GetMoveTreeNode(treeView));
                }

                foreach (PlayingPiece piece in counterAttackLosses.Keys)
                {
                    System.Windows.Forms.TreeNode combatLossNode = new System.Windows.Forms.TreeNode();
                    if (piece is GroundSupportUnit)
                        combatLossNode.Text = "GSU Destroyed";
                    else
                        combatLossNode.Text = counterAttackLosses[piece] + "-step loss";
                    if (!treeView.ImageList.Images.ContainsKey(piece.GetTreeViewImageListKey(false)))
                    {
                        if (piece is Block)
                        {
                            Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                            Graphics g = Graphics.FromImage(b);
                            PlayingPieceGraphics.PaintBlockFace(g, (Block)piece, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), false);
                            treeView.ImageList.Images.Add(piece.GetTreeViewImageListKey(false), b);
                        }
                        else if (piece is GroundSupportUnit)
                        {
                            Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                            Graphics g = Graphics.FromImage(b);
                            PlayingPieceGraphics.PaintGSUFace(g, (GroundSupportUnit)piece, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), false);
                            treeView.ImageList.Images.Add(piece.GetTreeViewImageListKey(false), b);
                        }
                    }

                    combatLossNode.ImageIndex = treeView.ImageList.Images.IndexOfKey(piece.GetTreeViewImageListKey(false));
                    combatLossNode.SelectedImageIndex = combatLossNode.ImageIndex;
                    counterAttackNode.Nodes.Add(combatLossNode);
                }

                nodeToReturn.Nodes.Add(counterAttackNode);
            }

            return nodeToReturn;
        }

        public override string GetStringForNetworkMessage()
        {
            return "Combat in " + Enum.GetName(typeof(MapInfo.RegionID), this.battleRegion);
        }
    }
}
